# -*- coding: utf-8 -*-
from typing import Sequence

from sqlalchemy import Select, select, desc, and_
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from sqlalchemy_crud_plus import CRUDPlus

from App.app.admin.models.sys_menu import SysMenu
# 动态导入模型和Schema
from App.app.admin.models.sys_role import SysRole
from App.app.admin.models.sys_user import SysUser
from App.app.admin.schemas.sys_role_schema import (
    CreateSysRoleParam,
    UpdateSysRoleParam, UpdateRoleMenuParam
)


class CRUDSysRole(CRUDPlus[SysRole]):
    async def get(self, db: AsyncSession, pk: int) -> SysRole | None:
        """
        获取角色详情

        :param db:
        :param pk:
        :return:
        """
        return await self.select_model(db, pk)

    async def get_list(self, name: str = None, status: str = None) -> Select:
        """
        获取角色列表

        :return:
        """
        stmt = (
            select(self.model)
            .options(selectinload(self.model.menus))
            .order_by(desc(self.model.status))
            .order_by(desc(self.model.created_time))
        )
        where_list = []
        if name:
            where_list.append(self.model.name.like(f'%{name}%'))
        if status:
            where_list.append(self.model.status == int(status))
        if where_list:
            stmt = stmt.where(and_(*where_list))
        # 打印生成的 SQL 语句
        # print(stmt.compile(compile_kwargs={"literal_binds": True}))
        return stmt

    async def get_all(self, db: AsyncSession) -> Sequence[SysRole]:
        """
        获取所有角色

        :param db:
        :return:
        """
        return await self.select_models(db)

    async def create(self, db: AsyncSession, obj_in: CreateSysRoleParam) -> SysRole:
        """
        创建角色

        :param db:
        :param obj_in:
        :return:
        """
        return await self.create_model(db, obj_in)

    async def update(self, db: AsyncSession, pk: int, obj_in: UpdateSysRoleParam) -> int:
        """
        更新角色

        :param db:
        :param pk:
        :param obj_in:
        :return:
        """
        return await self.update_model(db, pk, obj_in)

    async def delete(self, db: AsyncSession, pk: int) -> int:
        """
        删除角色

        :param db:
        :param pk:
        :return:
        """
        return await self.delete_model_by_column(db, allow_multiple=True, id=pk)

    async def get_with_relation(self, db, role_id: int) -> SysRole | None:
        """
        获取角色和菜单

        :param db:
        :param role_id:
        :return:
        """
        stmt = (
            select(self.model)
            .options(selectinload(self.model.menus))
            .where(self.model.id == role_id)
        )
        role = await db.execute(stmt)
        return role.scalars().first()

    async def get_by_user(self, db, user_id: int) -> Sequence[SysRole]:
        """
        获取用户角色
        :param db:
        :param user_id:
        :return:
        """
        stmt = select(self.model).join(self.model.users).where(SysUser.id == user_id)
        roles = await db.execute(stmt)
        return roles.scalars().all()

    async def get_by_name(self, db, name: str) -> SysRole | None:
        """
        根据名称获取角色
        :param db:
        :param name:
        :return:
        """
        return await self.select_model_by_column(db, name=name)

    async def update_menus(self, db, obj_in: UpdateRoleMenuParam) -> int:
        """
        更新角色菜单

        :param db:
        :param obj_in:
        :return:
        """
        current_role = await self.get_with_relation(db, obj_in.id)
        # 更新菜单
        stmt = select(SysMenu).where(SysMenu.id.in_(obj_in.menus))
        menus = await db.execute(stmt)
        current_role.menus = menus.scalars().all()
        return len(current_role.menus)


SysRoleDao: CRUDSysRole = CRUDSysRole(SysRole)
